package com.tau.egonetwork.gui.core;

import java.util.ArrayList;

import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.List;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;

import com.tau.egonetwork.profiles.FriendsList;
import com.tau.egonetwork.profiles.Gender;
import com.tau.egonetwork.profiles.MainProfile;
import com.tau.egonetwork.profiles.Profile;

public class ProfileEditDialog<T extends Comparable<T>> extends BasicDialog {
	
	protected Profile<T> profile;
	protected MainProfile<T> mainProfile;
		
	private final boolean editMode;
	private boolean changesWereMadeToProfile = false;
	
	private Text nameText;
	private Combo genderComboBox;
	private Text locationText;
	private Text workLocationText;
	
	private ArrayList<Profile<T>> friendsChanges;
	private ArrayList<Profile<T>> mutualFriendsList;
	
	/* constructor for editing: */
	public ProfileEditDialog(Shell parent, Profile<T> profile, MainProfile<T> mainProfile) {
		super(parent);
		this.profile = profile;
		this.mainProfile = mainProfile;
		this.editMode = true;
	}
		
	/* constructor for new: */
	public ProfileEditDialog(Shell parent, MainProfile<T> mainProfile) {
		super(parent);
		this.mainProfile = mainProfile;
		this.editMode = false;
	}
	
	@Override
	protected Object setReturnValue() {
		return changesWereMadeToProfile;
	}
	
	@Override
	protected void createWindowContents() {
				
		Composite basicDetailsComposite = new Composite(shell, SWT.NONE);
		basicDetailsComposite.setLayout(new GridLayout(2, false));
		basicDetailsComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));

		Label nameLabel = new Label(basicDetailsComposite, SWT.NONE);
		nameLabel.setText("Name: ");
		nameLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false));
		
		nameText = new Text(basicDetailsComposite, SWT.BORDER | SWT.FLAT);
		GridData nameTextLayoutData = new GridData(SWT.FILL, SWT.CENTER, true, false);
		nameTextLayoutData.widthHint = 180;
		nameText.setLayoutData(nameTextLayoutData);
		
		Label genderLabel = new Label(basicDetailsComposite, SWT.NONE);
		genderLabel.setText("Gender: ");
		genderLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false));
		
		genderComboBox = new Combo(basicDetailsComposite, SWT.DROP_DOWN);
		genderComboBox.add("Male", 0);
		genderComboBox.add("Female", 1);
		genderComboBox.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
		
		Label locationLabel = new Label(basicDetailsComposite, SWT.NONE);
		locationLabel.setText("Location: ");
		locationLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false));
		
		locationText = new Text(basicDetailsComposite, SWT.BORDER | SWT.FLAT);
		locationText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));

		Label workLocationLabel = new Label(basicDetailsComposite, SWT.NONE);
		workLocationLabel.setText("Work Location: ");
		workLocationLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false));
		
		workLocationText = new Text(basicDetailsComposite, SWT.BORDER | SWT.FLAT);
		workLocationText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));

		Composite friendsComposite = new Composite(shell, SWT.NONE);
		friendsComposite.setLayout(new GridLayout(2, false));
		friendsComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
		
		Label friendsLabel = new Label(friendsComposite, SWT.NONE);
		friendsLabel.setText("Friends: ");
		GridData friendsLabelGridData = new GridData(SWT.LEFT, SWT.CENTER, true, false);
		friendsLabelGridData.horizontalSpan = 2;
		friendsLabel.setLayoutData(friendsLabelGridData);
		
		final EgoNetworkComboBox<T> friendsComboBox = new EgoNetworkComboBox<T>(friendsComposite, SWT.DROP_DOWN);
		friendsComboBox.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
		
		Button addFriendButton = new Button(friendsComposite, SWT.PUSH | SWT.FLAT);
		addFriendButton.setText("Add");
		addFriendButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false));
		
		//build a list of all non-mutual friends and populate the combo with
		//it, so that each index corresponds with the list:
		final ArrayList<Profile<T>> nonMutualFriendsList = new ArrayList<Profile<T>>();
		if (mainProfile.getFriendsList() != null) {
			for (Profile<T> p : mainProfile.getFriendsList()) {
				//if not edit mode, add all friends to combo
				//if in edit mode, only add friends who are not mutual
				if (!editMode || profile.getFriendsList() == null || !profile.getFriendsList().contains(p)) {
					//also make sure you don't add yourself:
					if (!editMode || !p.equals(profile))
						nonMutualFriendsList.add(p);
				}			
			}
			//populate combo, if there's data to populate with:
			if (nonMutualFriendsList.size() == 0) {
				friendsComboBox.setEnabled(false);
			} else {
				//for (Profile<T> p : nonMutualFriendsList) {
				//	friendsComboBox.add(p.getName());
				//}
				friendsComboBox.setDatasource(nonMutualFriendsList);
			}
		} else {
			friendsComboBox.setEnabled(false);
			addFriendButton.setEnabled(false);
		}
				
		final List friendsList = new List(friendsComposite, SWT.BORDER | SWT.SINGLE | SWT.V_SCROLL);
		GridData friendsListGridData = new GridData(SWT.FILL, SWT.FILL, true, true);
		friendsListGridData.heightHint = 180;
		friendsListGridData.horizontalSpan = 2;
		friendsList.setLayoutData(friendsListGridData);
				
		//hold list of mutual friends to populate friendsList with:
		mutualFriendsList = new ArrayList<Profile<T>>();
		
		if (editMode) {
			
			nameText.setText(profile.getName());
			
			if (profile.getGender() != null) {	
				if (profile.getGender() == Gender.male)
					genderComboBox.select(0);
				else if (profile.getGender() == Gender.female)
					genderComboBox.select(1);
			}
			
			if (profile.getLocation() != null)
				locationText.setText(profile.getLocation());
			
			if (profile.getWorkLocation() != null)
				workLocationText.setText(profile.getWorkLocation());
		
			if (profile.getFriendsList() != null) {
				for (Profile<T> p : profile.getFriendsList()) {
					mutualFriendsList.add(p);
					friendsList.add(p.getName());
				}
			}

		}
		
		//hold a list (at first empty) of changes made to friends (for edit mode).
		//save changes when OK is clicked:
		friendsChanges = new ArrayList<Profile<T>>();

		addFriendButton.addListener(SWT.Selection, new Listener() {
			
			@Override
			public void handleEvent(Event event) {
				
				int selectedIndex = friendsComboBox.getSelectionIndex();
				if (selectedIndex < 0)
					return;
				
				Profile<T> selectedProfile = nonMutualFriendsList.get(selectedIndex);
				friendsList.add(selectedProfile.getName());
				//nonMutualFriendsList.remove(selectedProfile);
				mutualFriendsList.add(selectedProfile);
				friendsComboBox.remove(selectedIndex);
				friendsList.setSelection(friendsList.getItemCount() - 1);
				if (nonMutualFriendsList.size() == 0)
					friendsComboBox.setEnabled(false);
				
				if (editMode) {
					//addition/removal are symmetric: if user was originally a friend and
					//then removed, re-adding him will earse that change and vice versa.
					if (friendsChanges.contains(selectedProfile))
						friendsChanges.remove(selectedProfile);
					else
						friendsChanges.add(selectedProfile);
				}
			}
		});
		
		if (!(profile instanceof MainProfile<?>)) {
		
			Menu friendsListMenu = new Menu(friendsList);
			friendsList.setMenu(friendsListMenu);
			
			MenuItem deleteFriendMenuItem = new MenuItem(friendsListMenu, SWT.NONE);
			deleteFriendMenuItem.setText("Delete");
			deleteFriendMenuItem.addListener(SWT.Selection, new Listener() {
				
				@Override
				public void handleEvent(Event arg0) {
					
					int selectedIndex = friendsList.getSelectionIndex();
					if (selectedIndex < 0)
						return;
					
					Profile<T> selectedProfile = mutualFriendsList.get(selectedIndex);
					friendsList.remove(selectedProfile.getName());
					mutualFriendsList.remove(selectedProfile);
					nonMutualFriendsList.add(selectedProfile);
					friendsComboBox.refresh();
					friendsComboBox.setEnabled(true);
					
					if (editMode) {
						//addition/removal are symmetric: if user was originally a friend and
						//then removed, re-adding him will earse that change and vice versa.
						if (friendsChanges.contains(selectedProfile))
							friendsChanges.remove(selectedProfile);
						else
							friendsChanges.add(selectedProfile);
					}
				}
			});
		}
						
	}
	
	protected Profile<T> generateNewProfile(String name) {
		throw new NullPointerException("generateRandomID() method not implemented in subclass or ProfileEditDialog not subclassed for new operation");
	}

	@Override
	protected void onOKClicked() {

		if (nameText.getText() == null || nameText.getText().trim().equals("")) {
			MessageBox mbox = new MessageBox(shell, SWT.ICON_ERROR | SWT.OK);
			mbox.setText("Profile Details Error");
			mbox.setMessage("Profile name cannot be empty!");
			mbox.open();
			return;
		}

		if (editMode) {
			
			String dialogName = nameText.getText();
			int dialogGender = genderComboBox.getSelectionIndex();
			String dialogLocation = locationText.getText();
			String dialogWorkLocation = workLocationText.getText();
			
			if (!dialogName.trim().equals(profile.getName().trim())) {
				profile.setName(dialogName.trim());
				changesWereMadeToProfile = true;
			}
			
			switch (dialogGender) {
				case 0: //male
						if (profile.getGender() == null || profile.getGender() != Gender.male) {
							profile.setGender(Gender.male);
							changesWereMadeToProfile = true;
						}
						break;
				case 1: //female
					if (profile.getGender() == null || profile.getGender() != Gender.female) {
						profile.setGender(Gender.female);
						changesWereMadeToProfile = true;
					}
					break;
				default:
					if (profile.getGender() != null && profile.getGender() != Gender.undefined) {
						profile.setGender(Gender.undefined);
						changesWereMadeToProfile = true;
					}
			}
			
			if (dialogLocation == null || dialogLocation.trim().equals("")) {
				if (profile.getLocation() != null) {
					//make sure this is not about the empty string
					if (!profile.getLocation().trim().equals("")) {
						profile.setLocation(null);
						changesWereMadeToProfile = true;
					}
				}
			} else {
				if (profile.getLocation() == null
						|| !dialogLocation.trim().equals(profile.getLocation().trim())) {
					profile.setLocation(dialogLocation.trim());
					changesWereMadeToProfile = true;
				}
			}
			
			if (dialogWorkLocation == null || dialogWorkLocation.trim().equals("")) {
				if (profile.getWorkLocation() != null) {
					//make sure this is not about the empty string
					if (!profile.getWorkLocation().trim().equals("")) {
						profile.setWorkLocation(null);
						changesWereMadeToProfile = true;
					}
				}
			} else {
				if (profile.getWorkLocation() == null
						|| !dialogWorkLocation.trim().equals(profile.getWorkLocation().trim())) {
					profile.setWorkLocation(dialogWorkLocation.trim());
					changesWereMadeToProfile = true;
				}
			}
								
			if (friendsChanges.size() > 0) {
				
				FriendsList<T> friends = profile.getFriendsList();
				if (friends == null)
					friends = profile.createFriendsList();
				
				for (Profile<T> p : friendsChanges) {
					if (friends.contains(p)) {
						friends.remove(p);
						//remove from p as well:
						p.getFriendsList().remove(profile);
					} else {
						friends.add(p);
						//add to p as well:
						if (p.getFriendsList() == null)
							p.createFriendsList();
						p.getFriendsList().add(profile);
					}
				}
				
				changesWereMadeToProfile = true;
			}
		} else {
			
			Profile<T> newProfile = generateNewProfile(nameText.getText());
			
			if (genderComboBox.getSelectionIndex() == 0)
				newProfile.setGender(Gender.male);
			else if (genderComboBox.getSelectionIndex() == 1)
				newProfile.setGender(Gender.female);
			
			if (locationText.getText() != null && !locationText.getText().trim().equals(""))
				newProfile.setLocation(locationText.getText().trim());

			if (workLocationText.getText() != null && !workLocationText.getText().trim().equals(""))
				newProfile.setWorkLocation(workLocationText.getText().trim());
			
			if (mutualFriendsList.size() > 0) {
				FriendsList<T> friends = newProfile.createFriendsList();
				for (Profile<T> p : mutualFriendsList) {
					friends.add(p);
					if (p.getFriendsList() == null)
						p.createFriendsList();
					p.getFriendsList().add(newProfile);
				}
			}
			
			//most importantly - add new friend to main profile!:
			if (mainProfile.getFriendsList() == null)
				mainProfile.createFriendsList();
			
			mainProfile.getFriendsList().add(newProfile);
			changesWereMadeToProfile = true;
		}
		
		shell.close();

	}

}
